use std::{
    cell::UnsafeCell, mem::MaybeUninit, ops::Deref, time::{SystemTime, UNIX_EPOCH}
};

use sha2::{Digest, Sha256};

#[repr(transparent)]
pub struct UninitCell<T>(UnsafeCell<MaybeUninit<T>>);

unsafe impl<T: Send> Send for UninitCell<T> {}
unsafe impl<T: Sync> Sync for UninitCell<T> {}

impl<T> Deref for UninitCell<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { (&*self.0.get()).assume_init_ref() }
    }
}

impl<T> UninitCell<T> {
    pub const fn uninit() -> Self {
        Self(UnsafeCell::new(MaybeUninit::uninit()))
    }

    pub unsafe fn init_once(&self, value: T) {
        (&mut *self.0.get()).write(value);
    }
}

pub fn current_timestamp() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs()
}

pub fn token_create(id: &str) -> String {
    let mut hasher = Sha256::new();
    let now = current_timestamp();
    hasher.update(id.as_bytes());
    hasher.update(now.to_be_bytes());
    let hash = hasher.finalize();
    format!("{:x}", hash)
}
